package db

import (
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/google/uuid"
	"scase.io/application-auto-scaling-service/pkg/common"
	"time"
)

const (
	tableNameGroupPolicy = "group_policy_relation"
)

type GroupPolicyRelation struct {
	Id              string `orm:"column(id);size(64);pk"`
	ScalingGroupId  string `orm:"column(scaling_group_id);size(64)"`
	ScalingPolicyId string `orm:"column(scaling_policy_id);size(64)"`
	FleetId         string `orm:"column(fleet_id);size(64)"`
	TimeModel
}

type groupPolicyRelation struct{}

var relation = groupPolicyRelation{}

func GroupPolicyRelationTable() *groupPolicyRelation {
	return &relation
}

func (g *groupPolicyRelation) TableIndex() [][]string {
	return [][]string{
		{"ScalingGroupId"},
		{"ScalingPolicyId"},
		{"FleetId"},
	}
}

func (g *groupPolicyRelation) GetScalingPolicyIdsByGroupId(groupId string) ([]string, error) {
	list := []GroupPolicyRelation{}
	_, err := ormer.QueryTable(tableNameGroupPolicy).
		Filter(fieldNameScalingGroupId, groupId).
		Filter(fieldNameIsDeleted, notDeletedFlag).
		All(&list)
	if err != nil {
		return nil, err
	}
	policyIds := []string{}
	for _, rel := range list {
		policyIds = append(policyIds, rel.ScalingPolicyId)
	}
	return policyIds, nil
}

func (g *groupPolicyRelation) GetScalingGroupIdsByPolicyId(policyId string) ([]string, error) {
	list := []GroupPolicyRelation{}
	_, err := ormer.QueryTable(tableNameGroupPolicy).
		Filter(fieldNameScalingPolicyId, policyId).
		Filter(fieldNameIsDeleted, notDeletedFlag).
		All(&list)
	if err != nil {
		return nil, err
	}
	groupIds := []string{}
	for _, rel := range list {
		groupIds = append(groupIds, rel.ScalingPolicyId)
	}
	return groupIds, nil
}

func (g *groupPolicyRelation) GetRelation(fleetId, groupId, policyId string, limit, offset int) ([]GroupPolicyRelation, error) {
	list := []GroupPolicyRelation{}
	qs := ormer.QueryTable(tableNameGroupPolicy)
	condition := orm.NewCondition()
	if len(fleetId) != 0 {
		condition = condition.And(fieldNameFleetId, fleetId)
	}
	if len(groupId) != 0 {
		condition = condition.And(fieldNameScalingGroupId, groupId)
	}
	if len(policyId) != 0 {
		condition = condition.And(fieldNameScalingPolicyId, policyId)
	}
	if limit <= 0 {
		limit = common.DefaultLimit
	}
	if offset <= 0 {
		offset = common.DefaultOffset
	}
	condition = condition.And(fieldNameIsDeleted, notDeletedFlag)
	_, err := qs.SetCond(condition).Limit(limit).Offset(limit * offset).All(&list)
	if err != nil {
		return nil, err
	}

	return list, nil
}

func (g *groupPolicyRelation) InsertRelation(fleetId, groupId, policyId string) error {
	_, err := ormer.Insert(&GroupPolicyRelation{
		Id:              uuid.NewString(),
		ScalingGroupId:  groupId,
		ScalingPolicyId: policyId,
		FleetId:         fleetId,
		TimeModel:       TimeModel{IsDeleted: notDeletedFlag},
	})
	return err
}

func (g *groupPolicyRelation) DeleteRelation(groupId, policyId string) error {
	num, err := ormer.QueryTable(tableNameGroupPolicy).
		Filter(fieldNameScalingGroupId, groupId).
		Filter(fieldNameScalingPolicyId, policyId).
		Filter(fieldNameIsDeleted, notDeletedFlag).
		Update(orm.Params{
			fieldNameIsDeleted: deletedFlag,
			fieldNameDeleteAt:  time.Now().UTC(),
		})
	if num == 0 {
		return fmt.Errorf("relation of group [%s] and policy [%s] not exist", groupId, policyId)
	}
	return err
}

func (g *groupPolicyRelation) CheckRelationExist(groupId, policyId string) bool {
	qs := ormer.QueryTable(tableNameGroupPolicy)
	condition := orm.NewCondition()
	if len(groupId) != 0 {
		condition = condition.And(fieldNameScalingGroupId, groupId)
	}

	if len(policyId) != 0 {
		condition = condition.And(fieldNameScalingPolicyId, policyId)
	}
	condition = condition.And(fieldNameIsDeleted, notDeletedFlag)

	return qs.SetCond(condition).Exist()
}
